package com.cheifsteam.springframework.beans.factory.xml;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import com.cheifsteam.springframework.beans.BeansException;
import com.cheifsteam.springframework.beans.PropertyValue;
import com.cheifsteam.springframework.beans.factory.config.BeanDefinition;
import com.cheifsteam.springframework.beans.factory.config.BeanReference;
import com.cheifsteam.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import com.cheifsteam.springframework.beans.factory.support.BeanDefinitionRegistry;
import com.cheifsteam.springframework.core.io.Resource;
import com.cheifsteam.springframework.core.io.ResourceLoader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author 屈燃希
 * @date 2025/1/24 15:39
 * @content
 */
public class XmlBeanDefinitionReader  extends AbstractBeanDefinitionReader {
    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        super(registry);

    }

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
        super(registry, resourceLoader);
    }

    @Override
    public void loadBeanDefinitions(String locations) {
        Resource resource = getResourceLoader().getResource(locations);
        loadBeanDefinitions(resource);
    }

    @Override
    public void loadBeanDefinitions(String[] locations) {
        for (String location : locations) {
            loadBeanDefinitions(location);
        }
    }

    @Override
    public void loadBeanDefinitions(Resource resource) {
        try {
            InputStream inputStream = resource.getInputStream();
            doLoadBeanDefinitions(inputStream);
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void loadBeanDefinitions(Resource... resources) {
        for (Resource resource : resources) {
            loadBeanDefinitions(resource);
        }
    }


    public void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {

        Document document = XmlUtil.readXML(inputStream);
        Element root = document.getDocumentElement();
        NodeList childNodes = root.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            if (!(childNodes.item(i) instanceof Element)){continue;}
            if (!"bean".equals(childNodes.item(i).getNodeName())){continue;}
            Element bean = (Element) childNodes.item(i);
            String id = bean.getAttribute("id");
            String name = bean.getAttribute("name");
            String className = bean.getAttribute("class");

            String initMethod = bean.getAttribute("init-method");
            String destroyMethodName = bean.getAttribute("destroy-method");
            String scope = bean.getAttribute("scope");


            Class<?> clazz = Class.forName(className);
            String beanName = StrUtil.isNotEmpty(id) ? id : name;
            if (StrUtil.isEmpty(beanName)) {
                beanName = StrUtil.lowerFirst(clazz.getSimpleName());
            }
            BeanDefinition beanDefinition = new BeanDefinition(clazz);
            beanDefinition.setInitMethodName(initMethod);
            beanDefinition.setDestroyMethodName(destroyMethodName);

            if (StrUtil.isNotEmpty(scope)) {
                beanDefinition.setScope(scope);
            }

            for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
                if (!(bean.getChildNodes().item(j) instanceof Element)) {continue;}
                if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) {continue;}
                //解析property
                Element property = (Element) bean.getChildNodes().item(j);
                String attrName = property.getAttribute("name");
                String attrValue = property.getAttribute("value");
                String attrRef = property.getAttribute("ref");
                if (StrUtil.isNotEmpty(attrValue)) {
                    beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(attrName, attrValue));
                } else if (StrUtil.isNotEmpty(attrRef)) {
                    beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(attrName, new BeanReference(attrRef)));
                }


            }
            if (getRegistry().containsBeanDefinition(beanName)) {
                throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
            }
            // 注册 BeanDefinition
            getRegistry().registerBeanDefinition(beanName, beanDefinition);
        }
    }
}
